//
// Created by root on 2/18/18.
//

#include <dirent.h>
#include <memory.h>
#include "component.h"
#include "../config/global.h"
#include "../base/cmemory.h"
#include "../base/utils.h"

#define MAX_SIZE       512

#define CATEGORY_CHAR  '='
#define DELIMITER_CHAR ';'
#define FUNCTIONS  "functions"
#define CLASSES    "classes"

static int dir_existed(String basePath, String dirName) {
    String path = append_path(basePath, dirName);
    DIR *dir;
    if ((dir = opendir(path)) == NULL) {
        return FALSE;
    }
    closedir(dir);
    return TRUE;
}

void cache_component_path(String component) {
    String *basePaths = globalFunny->repoPaths;
    while (*basePaths) {
        if (dir_existed(*basePaths, component)) {
            hashmap_put(globalFunny->componentPaths, component, *basePaths);
            break;
        }
        basePaths++;
    }
}

void *build_component(FILE *metaFile) {
    Component *component = (Component *) sys_malloc(sizeof(Component));
    int c = 0;
    String category = NULL;

    while (TRUE) {
        c = getc(metaFile);

        if (c == -1)
            break;

        if (c == CATEGORY_CHAR) {
            //category = get_category(metaFile, '='); //todo
            if (equals_string(category, FUNCTIONS)) {
                Queue *functions = parse_functions_meta_data(metaFile);
                component->functions = functions;
            }
            else if (equals_string(category, CLASSES)) {
                Queue *classes = parse_classes_meta_data(metaFile); //Queue<Tree>
                component->classes = classes;
            }
            else {
                ;
            }
        }
    }
    return component;
}

Queue *parse_functions_meta_data(FILE *metaFile) {
    //todo

    return NULL;
}

Queue *parse_classes_meta_data(FILE *metaFile) {
    //todo

    return NULL;
}

void build_meta_data(Queue *queue) {
    //1. determine orders to translate
    //2. form functions and class inheritance

    globalFunny->modules = init_queue();
    globalFunny->functions = init_queue();
    globalFunny->inheritance = init_tree();

    QueueNode *node = queue->head;
    while (node != NULL) {
        Component *component = (Component *)(node->element);
        do_with_functions(component->functions);
        node = node->next;
    }

    node = queue->head;
    while (node != NULL) {
        Component *component = (Component *)(node->element);
        do_with_classes(component->classes);
        node = node->next;
    }
}

void do_with_functions(Queue *functions) {
    QueueNode *node = functions->head;
    while (node != NULL) {
        FunctionMeta *functionMeta = (FunctionMeta *)(node->element);
        enqueue(globalFunny->modules, functionMeta->moduleName);
        append_queue(globalFunny->functions, functionMeta->functions);
        node = node->next;
    }
}


void do_with_classes(Queue *classTrees) {
    QueueNode *node = classTrees->head;
    while (node != NULL) {
        Tree *tree = (Tree *)(node->element);
        TreeNode *treeNode = tree->root;
        do_with_class_module(treeNode); // travel tree and enqueue module
        merge_tree(tree);
        node = node->next;
    }
}

void do_with_class_module(TreeNode *node) {
    if (node != NULL) {
        ClassMeta *classMeta = (ClassMeta *)(node->data);
        enqueue(globalFunny->modules, classMeta->moduleName);

        QueueNode *queueNode = node->children->head;
        while (queueNode != NULL) {
            do_with_class_module((TreeNode *)(queueNode->element));
            queueNode = queueNode->next;
        }
    }
}

void merge_tree(Tree *tree) {
    if (globalFunny->inheritance == NULL) {
        globalFunny->inheritance = init_tree();

        // globalFunny->inheritance->root = ObjectNode; todo
    }
    String rootName = tree->root->name;
    TreeNode *node = tree_find(globalFunny->inheritance, rootName);
    if (node == NULL) {
        ; //todo
    } else {
        append_queue(node->children, tree->root->children);
    }
}


static char* convert_name(char* string) {
    char open = '[';
    char close = ']';

    if (strchr(string, open) == NULL) {
        return string;
    }

    char *str = copy_string(string);
    char *start = str;
    char *end = str;
    char *result = (char *)sys_malloc((strlen(string) + 20) * sizeof(char));

    while(*str) {
        if (*str == open) {
            start = str;
        } else if (*str == close) {
            end = str;
            break;
        }
        str++;
    }
    start++;
    end--;

    int n = end - start + 1;
    strncpy(result, start, n);
    end += 2;
    while (IS_SPACE(*end)) end++;
    start = end;
    while (*end) end++;
    strncpy(result + n, "/", 1);
    strncpy(result + n + 1, start, end - start + 1);

    return result;
}

String hierarchy(Statement *s) {
    String data = extract_string(extract_content(s));
    data = trim_string(data);
    globalFunny->inheritance = construct_tree(globalFunny->inheritance, data, '-', convert_name);
    ;
    return NULL;
}

/*
static void translate_file(const char *source, const char *target, const char *package) {
    globalFunny->package = package; //package
    remove(target);
    FILE *fout = fopen(target, "w");
    if (!fout) {
        perror(target);
        exit(EXIT_FAILURE);
    }
    FILE *fin = fopen(source, "rb");
	if (!fin) {
		perror(source);
		exit(EXIT_FAILURE);
	}
    Statement *s = NULL;
    while (has_next_statement(fin)) {
		s = next_statement(fin);
		String r = match(s);
		if (r != NULL) {
			fprintf(fout, "%s\n", r);
		}
	}
	fclose(fin);
	fclose(fout);
}

static void translate_dir(String dirPath) {
	DIR *dir;
	struct dirent *ptr;

	if ((dir = opendir(dirPath)) == NULL) {
		perror(dirPath);
		return;
	}
	while ((ptr = readdir(dir)) != NULL) {
		if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
			continue;
		}
		if (ptr->d_type == DT_DIR) { //dir
			String innerDir = append_path(dirPath, ptr->d_name);
			translate_dir(innerDir);
		} else if (ptr->d_type == DT_REG && has_suffix(ptr->d_name, FUNNY_FILE_EXTENSION)) { //file
			String source = append_path(dirPath, ptr->d_name);
            String target = change_suffix(source, FUNNY_FILE_EXTENSION, SCHEME_FILE_EXTENSION);
			translate_file(source, target, NULL); //how to record package?
		}
	}
	closedir(dir);
}

String translate(Statement *s) {
	String fileOrDirectory = extract(s);
	if (has_suffix(fileOrDirectory, FUNNY_FILE_EXTENSION)) {
		String source = append_path(globalFunny->basePath, fileOrDirectory);
		String target = change_suffix(source, FUNNY_FILE_EXTENSION, SCHEME_FILE_EXTENSION);

        String package = copy_string(fileOrDirectory);
        char *p = strrchr(package, '/');
        if (p) {
            *p = '\0';
        } else {
            package = NULL;
        }
		translate_file(source, target, package);
	} else {
		String dirPath = append_path(globalFunny->basePath, fileOrDirectory);
		translate_dir(dirPath);
	}
}

String publish(Statement *s) {
	return NULL;
}
*/
